package com.tbit.uqbike.compalint.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.huifu.adapay.core.exception.BaseAdaPayException;
import com.huifu.adapay.model.AdapayCommon;
import com.tbit.common.config.OssDefaultConfig;
import com.tbit.config.payConfig.AdapayConfigUtil;
import com.tbit.uqbike.compalint.enums.ComplaintStatusEnum;
import com.tbit.uqbike.compalint.enums.PlatformEnum;
import com.tbit.uqbike.compalint.mapper.ComplaintHistoryMapper;
import com.tbit.uqbike.compalint.mapper.ComplaintMapper;
import com.tbit.uqbike.compalint.param.*;
import com.tbit.uqbike.compalint.service.base.AbstractComplaintService;
import com.tbit.uqbike.compalint.table.ComplaintDO;
import com.tbit.uqbike.compalint.table.ComplaintHistoryDO;
import com.tbit.uqbike.manager.exception.BaseException;
import com.tbit.uqbike.object.pojo.AdaPayConfig;
import com.tbit.uqbike.webmanager.dao.core.AdaPayConfigDao;
import com.tbit.uqbike.webmanager.util.aliyun.OssFileUtils;
import com.tbit.utils.Base64ImageUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 汇付客诉api
 *
 * @author <a href="mailto:zhang.zhiliang@tbit.com.cn">Zhang ZhiLiang</a>
 * @version 1.0
 * @see <a href="http://adsl1.tbit.com.cn:21490/pages/viewpage.action?pageId=82182491">订单号规范</a>
 * @since 2025/2/14
 */
@Slf4j
@Service(value = "adapayComplaintService")
public class AdapayComplaintService extends AbstractComplaintService {

    private final AdaPayConfigDao adaPayConfigDao;

    @Autowired
    public AdapayComplaintService(ComplaintMapper complaintMapper, ComplaintHistoryMapper complaintHistoryMapper, OssDefaultConfig ossDefaultConfig, AdaPayConfigDao adaPayConfigDao) {
        super(complaintMapper, complaintHistoryMapper, ossDefaultConfig);
        this.adaPayConfigDao = adaPayConfigDao;
    }

    /**
     * 汇付客诉 - 回复用户留言api
     * @param param 回复用户客诉留言参数
     * @return 是否成功
     */
    @Override
    public Boolean responseApi(ComplaintResponseParam param) {
        // 查询汇付配置
        AdaPayConfig adaPayConfig = adaPayConfigDao.getByBrandId(param.getBrandId());
        if (Objects.isNull(adaPayConfig)){
            throw new BaseException(String.format("%s汇付品牌配置为空,回复失败", param.getBrandId()));
        }
        Map<String, Object> responseParam = new HashMap<String, Object>();
        responseParam.put("adapay_func_code", "wechatComplaint.reply");
        responseParam.put("complaint_id", param.getComplaintId());
        responseParam.put("response_content", param.getContent());
        try {
            AdapayCommon.requestAdapay(responseParam, AdapayConfigUtil.getMchConfigKey(adaPayConfig));
            return true;
        } catch (BaseAdaPayException e) {
            log.error("投诉单号{}客诉回复失败",param.getComplaintId(),e);
            return false;
        }
    }

    /**
     * 汇付客诉 - 拉取客诉最新状态
     * @param param 客诉状态拉取参数
     * @return 格式化后的平台状态枚举
     * todo 汇付暂时未提供更具单号查询客诉详情功能 ， 暂时先用列表接口实现，等提供后再替换
     */
    @Override
    public ComplaintStatusEnum getDetailApi(ComplaintVerifyParam param) {
        // 查询汇付配置
        AdaPayConfig adaPayConfig = adaPayConfigDao.getByBrandId(param.getBrandId());
        if (Objects.isNull(adaPayConfig)){
            log.warn(String.format("%s汇付品牌配置为空,状态获取失败", param.getBrandId()));
            return null;
        }
        ComplaintDO complaintDO = complaintMapper.selectOne(new LambdaQueryWrapper<ComplaintDO>().eq(ComplaintDO::getComplaintId, param.getComplaintId()));
        String complaintDate = complaintDO.getComplaintTime().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        // 请求参数
        Map<String, Object> detailParam = new HashMap<String, Object>();
        detailParam.put("adapay_func_code", "wechatComplaint.list");
        detailParam.put("begin_date", complaintDate);
        detailParam.put("end_date", complaintDate);
        detailParam.put("pageIndex", 1);
        detailParam.put("pageSize",100);
        try {
            Map<String, Object> result = AdapayCommon.queryAdapay(detailParam,AdapayConfigUtil.getMchConfigKey(adaPayConfig));

            // 构造返回参数
            return getAdapayComplaintStatus_temp(complaintDO.getStatus(),param.getComplaintId(),result);
        } catch (BaseAdaPayException e) {
            log.error("投诉单号{}客诉详情获取失败",param.getComplaintId(),e);
            return null;
        }
    }


    /**
     * 查询客诉具体状态 - 临时方法
     * @param status 当前数据库客诉状态
     * @param complaintId 客诉单号
     * @param result 获取客诉列表api的返回结果
     * @return 汇付返回的状态字符串
     * todo 汇付暂时未提供更具单号查询客诉详情功能 ， 暂时先用列表接口实现，等提供后再替换
     */
    private ComplaintStatusEnum getAdapayComplaintStatus_temp(Integer status, String complaintId,Map<String, Object> result){
        Object res = result.get("list");
        if (Objects.isNull(res)){
            return ComplaintStatusEnum.getByCode(status);
        }
        JSONArray jsonArray = JSONArray.parseArray(res.toString());
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject jsonObject = jsonArray.getJSONObject(i);
            if (Objects.equals(complaintId,jsonObject.getString("complaint_id"))){
                return ComplaintStatusEnum.getComplaintEnumByAdapay(jsonObject.getString("complaint_state"));
            }
        }
        return null;
    }


    /**
     * 汇付客诉 - 客诉协商历史查询
     * @param param 客诉协商历史查询参数
     * @return 客诉协商历史
     */
    @Override
    public List<ComplaintHistoryDO> getHistoryDetailApi(ComplaintHistoryParam param) {
        // 查询汇付配置
        AdaPayConfig adaPayConfig = adaPayConfigDao.getByBrandId(param.getBrandId());
        if (Objects.isNull(adaPayConfig)){
            log.warn(String.format("%s汇付品牌配置为空,拉取协商历史失败", param.getBrandId()));
            return new ArrayList<ComplaintHistoryDO>();
        }
        // 请求参数
        Map<String, Object> detailParam = new HashMap<String, Object>();
        detailParam.put("adapay_func_code", "wechatComplaint.historyDetail");
        detailParam.put("complaint_id", param.getComplaintId());
        detailParam.put("pageIndex", 1);
        try {
            Map<String, Object> result = AdapayCommon.queryAdapay(detailParam, AdapayConfigUtil.getMchConfigKey(adaPayConfig));
            return parseToComplaintHistoryList(param.getComplaintId(), result, AdapayConfigUtil.getMchConfigKey(adaPayConfig));
        } catch (BaseAdaPayException e) {
            log.error("投诉单号{}客诉详情获取失败",param.getComplaintId(),e);
            return new ArrayList<ComplaintHistoryDO>();
        }
    }

    /**
     * 解析汇付协商历史返回结果
     * @param complaintId 投诉单号
     * @param result 汇付协商历史api返回结果
     * @param mchConfigKey 汇付商户配置key
     * @return 客诉协商历史数据库实体列表
     */
    private List<ComplaintHistoryDO> parseToComplaintHistoryList(String complaintId, Map<String, Object> result, String mchConfigKey) {
        // 构造返回参数
        List<ComplaintHistoryDO> complaintHistoryDOList = new ArrayList<>();
        Object resList = result.get("list");
        if (Objects.isNull(resList)){
            log.warn("投诉单号{}拉取客诉协商历史列表为空",complaintId);
            return complaintHistoryDOList;
        }
        JSONArray jsonArray = JSONArray.parseArray(resList.toString());
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject jsonObject = jsonArray.getJSONObject(i);
            String picture = dealPicture_History(jsonObject.getJSONObject("complaint_media_list"), complaintId, mchConfigKey);
            complaintHistoryDOList.add(new ComplaintHistoryDO().setComplaintId(complaintId).setUuid(jsonObject.getString("log_id"))
                    .setPicture(picture).setContent(jsonObject.getString("operate_details"))
                    .setSender(!Objects.equals(COMPLAINANT, jsonObject.getString("operator")) ? SYSTEM : COMPLAINANT).setAdminFlag(!Objects.equals(COMPLAINANT, jsonObject.getString("operator")))
                    .setSendTime(LocalDateTime.parse(jsonObject.getString("operate_time"), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))));
        }
        return complaintHistoryDOList;
    }

    /**
     * 处理汇付客诉文件
     * 1. 下载文件base64编码
     * 2. 将base64编码转换成图片
     * 3. 上传oss
     * 4. 将oss文件url 拼接返回
     * @param complaintMediaArray 汇付客诉文件对象
     * @param complaintId 客诉单号
     * @param mchConfigKey 汇付商户的配置key
     * @return oss文件地址字符串
     */
    private String dealPicture(JSONArray complaintMediaArray, String complaintId, String mchConfigKey) {
        if (Objects.isNull(complaintMediaArray)){
            return null;
        }
        StringBuilder picture = new StringBuilder();
        for (int x = 0; x < complaintMediaArray.size(); x++) {
            JSONObject complaintMediaObject = complaintMediaArray.getJSONObject(x);
            JSONArray mediaUrl = complaintMediaObject.getJSONArray("media_url");
            for (int i = 0; i < mediaUrl.size(); i++) {
                String url = mediaUrl.getString(i);
                String fileBase64Str = getFileBase64Str(url, complaintId, mchConfigKey);
                try {
                    ByteArrayInputStream byteArrayInputStream = Base64ImageUtil.base64ToInputStream(fileBase64Str);
                    String ossUrl = OssFileUtils.uploadByAliYun(byteArrayInputStream, getOssConfig(), String.format("complaint/Adapay-picture-%s",UUID.randomUUID()), "image/jpeg", OssFileUtils.IMAGE);
                    picture.append(ossUrl).append(";");
                } catch (IOException e) {
                    log.error("投诉单号{}文件获取字节流失败", complaintId, e);
                } catch (Exception e) {
                    log.error("投诉单号{}文件上传oss失败", complaintId, e);
                }
            }
        }
        if (picture.length() > 0){
            picture.delete(picture.length()-1, picture.length());
        }
        return picture.toString();
    }

    /**
     * 处理汇付客诉文件
     * 1. 下载文件base64编码
     * 2. 将base64编码转换成图片
     * 3. 上传oss
     * 4. 将oss文件url 拼接返回
     *
     * @param complaintMediaObject 汇付客诉文件对象
     * @param complaintId          客诉单号
     * @param mchConfigKey         汇付商户的配置key
     * @return oss文件地址字符串
     */
    private String dealPicture_History(JSONObject complaintMediaObject, String complaintId, String mchConfigKey) {
        if (Objects.isNull(complaintMediaObject)) {
            return null;
        }
        JSONArray complaintMediaArray = complaintMediaObject.getJSONArray("media_url");
        StringBuilder picture = new StringBuilder();
        for (int x = 0; x < complaintMediaArray.size(); x++) {

            String url = complaintMediaArray.getString(x);
            String fileBase64Str = getFileBase64Str(url, complaintId, mchConfigKey);
            try {
                ByteArrayInputStream byteArrayInputStream = Base64ImageUtil.base64ToInputStream(fileBase64Str);
                String ossUrl = OssFileUtils.uploadByAliYun(byteArrayInputStream, getOssConfig(), String.format("complaint/Adapay-picture-%s", UUID.randomUUID()), "image/jpeg", OssFileUtils.IMAGE);
                picture.append(ossUrl).append(";");
            } catch (IOException e) {
                log.error("投诉单号{}文件获取字节流失败", complaintId, e);
            } catch (Exception e) {
                log.error("投诉单号{}文件上传oss失败", complaintId, e);
            }

        }
        if (picture.length() > 0) {
            picture.delete(picture.length() - 1, picture.length());
        }
        return picture.toString();
    }

    /**
     * 汇付下载客诉文件
     * @param url 客诉文件地址
     * @param complaintId 客诉单号
     * @param mchConfigKey 汇付商户配置的key
     * @return 文件的base64编码字符串
     */
    private String getFileBase64Str(String url, String complaintId, String mchConfigKey){
        // 请求参数
        Map<String, Object> param = new HashMap<String, Object>();
        param.put("adapay_func_code", "wechatComplaint.download");
        param.put("complaint_id", complaintId);
        param.put("media_url", url);
        String base64Url = null;
        try {
            Map<String, Object> result = AdapayCommon.requestAdapay(param,mchConfigKey);
            base64Url = result.get("media_data").toString();
        } catch (BaseAdaPayException e) {
            log.error("投诉单号{}文件下载失败",complaintId,e);
        }
        return base64Url;
    }

    @Override
    public Boolean completeApi(ComplaintCompleteParam param) {
        // 查询汇付配置
        AdaPayConfig adaPayConfig = adaPayConfigDao.getByBrandId(param.getBrandId());
        if (Objects.isNull(adaPayConfig)){
            log.warn(String.format("%s汇付品牌配置为空,反馈客诉完成失败", param.getBrandId()));
            return false;
        }
        // 请求参数
        Map<String, Object> completeParam = new HashMap<String, Object>();
        completeParam.put("adapay_func_code", "wechatComplaint.complete");
        completeParam.put("complaint_id", param.getComplaintId());
        try {
            AdapayCommon.requestAdapay(completeParam);
            return true;
        } catch (BaseAdaPayException e) {
            log.error("投诉单号{}反馈客诉状态失败",param.getComplaintId(),e);
            return false;
        }
    }

    /**
     * 汇付平台拉取客诉
     * @param param 客诉拉取参数
     * @return
     */
    @Override
    public List<ComplaintDO> pullComplaintApi(ComplaintPullParam param) {
        // 查询汇付配置
        AdaPayConfig adaPayConfig = adaPayConfigDao.getByBrandId(param.getBrandId());
        if (Objects.isNull(adaPayConfig)){
            log.warn(String.format("%s汇付品牌配置为空,拉取客诉列表失败", param.getBrandId()));
            return new ArrayList<ComplaintDO>();
        }
        String begin_date = LocalDateTime.parse(param.getStartTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")).format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        String end_date = LocalDateTime.parse(param.getEndTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")).format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        // 请求参数
        Map<String, Object> detailParam = new HashMap<String, Object>();
        detailParam.put("adapay_func_code", "wechatComplaint.list");
        detailParam.put("begin_date", begin_date);
        detailParam.put("end_date", end_date);
        // 根据offset 推演 pageNum ， 当页大小为 20 页 时 ， 当前偏移为 25 ， 则页码为 2 ， 拉取的数据会有 5条重复 ， 入库时做了清洗
        int pageIndex = param.getOffset()/param.getLimit() + 1;
        detailParam.put("pageIndex", pageIndex);
        detailParam.put("pageSize",param.getLimit());
        try {
            Map<String, Object> result = AdapayCommon.queryAdapay(detailParam,AdapayConfigUtil.getMchConfigKey(adaPayConfig));
            // 构造返回参数
            return parseToComplaintDO(adaPayConfig,result);
        } catch (BaseAdaPayException e) {
            log.error("拉取客诉详情获取失败",e);
            return new ArrayList<ComplaintDO>();
        }
    }

    /**
     * 解析汇付客诉列表返回结果
     * @param adaPayConfig 汇付配置
     * @param result 汇付客诉列表返回结果api
     * @return 数据库实体列表
     */
    private List<ComplaintDO> parseToComplaintDO(AdaPayConfig adaPayConfig, Map<String, Object> result) {
        List<ComplaintDO> complaintDOList = new ArrayList<>();
        Object object = result.get("list");
        if (Objects.isNull(object)){
            return complaintDOList;
        }
        JSONArray jsonArray = JSONArray.parseArray(object.toString());
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject jsonObject = jsonArray.getJSONObject(i);
            Integer orderMoney = new BigDecimal(jsonObject.getString("amount")).multiply(new BigDecimal(100)).setScale(0, RoundingMode.HALF_UP).intValue();
            String complaintId = jsonObject.getString("complaint_id");
            String picture = dealPicture(jsonObject.getJSONArray("complaint_media_list"), complaintId, AdapayConfigUtil.getMchConfigKey(adaPayConfig));
            complaintDOList.add(
                    new ComplaintDO().setBrandId(adaPayConfig.getAccountId()).setComplaintId(complaintId)
                            .setComplaintTime(LocalDateTime.parse(jsonObject.getString("complaint_time"), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
                            .setPlatform(PlatformEnum.ADAPAY.getCode())
                            .setOrderMoney(orderMoney).setDescription(jsonObject.getString("complaint_detail"))
                            .setPicture(picture).setPhone(jsonObject.getString("payer_phone"))
                            .setOrderNO(jsonObject.getString("out_trade_no"))
                            .setStatus(ComplaintStatusEnum.NEW.getCode())
            );
        }
        return complaintDOList;
    }
}
